Agenda
- revisit reproducible workflow
- some review of STAT 184 topics
Homework
- (late) Generic R Notebook
- (late) GitHub Startup
- (friday) Programming Notebooks: MDSR Chapter 04
- (sunday) Programming Notebooks: MDSR Chapter 03
- (next week) MDSR Chap 3 Exercises
- (next week) Programming Notebooks: MDSR Chapter 05
STAT 380 workflow
- Reproducible Research
- Git(Hub) source control basics
- RStudio IDE (R, Rmd, Git)
Git / GitHub
- GitHub’s Intro: https://guides.github.com/activities/hello-world/
- “GitHub is a code hosting platform for version control and collaboration. It lets you and others work together on projects from anywhere.”
- Repositories are used to organize each project
- These can contain documents, images, folders, code, data, … basically everything you need for your project
- Larger files (> 10-15 MB) need some special handling, but usually not a big deal
- You’ll soon link each GitHub Repository to an RStudio Project to streamline the workflow
- Don’t put repositories inside other repositories
- Most of your workflow is unchanged
- As far as your computer is concerned, the repository works just like any other directory (i.e. folder)
- You edit files, save changes, etc
Git / GitHub
- First new part: (commit) changes
- ideally, each commit should encompass one meaningful modification
- creates a permanent snapshot of the repository
- you can revisit these snapshots at any time…
- Second new part: (push/pull) to remote
- GitHub stores the state of your repository in the cloud
- When you push, you update the remote version
- Anyone with access to your GitHub repository can pull the remote version and work with it
- This might be you, using a different computer
- It might be a collaborator
- It might be a professor or TA
- If the repo is made public, it might be a complete stranger!
- The collaborator can then commit changes and push them to the remote as well
- don’t worry, there are safeguards in place based on user permissions
Git / GitHub
- Once configured, nearly all of the action can happen in RStudio
- A “Git” tab will appear in RStudio
- Diff, Commit, Pull, Push are most common actions
Markdown / R Markdown
- Human-readable syntax by design
- Can “knit” (or preview) same .Rmd to HTML (or PDF or MS Word with some configuration)
- Can produce both notebook, slides, document, webpage, etc as output.
- Regardless of intended output, Rmd documents generally require two parts
- “yaml” header at the top (designated by
---
before/after) includes some document controls
- title
- author
- date
- output
- (etc)
- body of the document including components such as:
- Markdown syntax (like hashtag headers)
- Narrative text
- Lists (bullets or numbers)
- Code “chunks” (R, python, SQL, Stan, etc embedded among the narrative of the document)
- URLs
- Images
- Tables
- and much more…
Why RMarkdown?
RMarkdown lets us separate content from formatting
- Alternative to WYSIWYG’s like MS Word & Google Docs
- Easy to configure headings, lists, TOC, figures, captions, links, images, etc
- Change formatting globally with a css (cascading style sheet)
- Good-looking tables are easy
- Typeset nice-looking mathematics using LaTeX (and some preview)
STAT 501 excerpt (inline math)…
Here’s the model:
\(log(\frac{\hat{p}_i}{1-\hat{p}_i}) = 3.309 - 0.288(dist_i)\)
where \(\hat{p}_i\) is the proportion that voted “Yes” for community i.
Since the relationship on a logarithmic scale is hard to interpret, we back transform before interpreting coefficients.
Note: If \(e^{\beta_1} = 1\), then it means the odds are 1:1 which translates to a 50-50 chance and means there would be no relationship between the explanatory variable and the odds of “success” (however that’s defined in the context of the study).
STAT 501 excerpt (aligned to =
sign)…
\[\begin{align*}
\mathit{SSE} &= \Sigma_{i} \left( y_{i} - b_{0} - b_{1}x_{i} \right)^2 \\
\\
\frac{\partial \left( SSE \right)}{\partial b_{0}} &= \Sigma_{i} \left( y_{i} - b_{0} - b_{1}x_{i} \right)^2 \\
&= \left( -2 \right) \Sigma_{i} \left( y_{i} - b_{0} - b_{1}x_{i} \right) \\
&= \left( -2 \right) \left( \Sigma y_{i} - \Sigma b_{0} - \Sigma b_{1}x_{i} \right) \\
\\
\frac{\partial \left( SSE \right)}{\partial b_{1}} &= \Sigma_{i} \left( y_{i} - b_{0} - b_{1}x_{i} \right)^2 \\
&= \Sigma_{i} \left( -2x_{i} \right) \left( y_{i} - b_{0} - b_{1}x_{i} \right) \\
&= \left( -2\right) \Sigma_{i} \left( x_{i} y_{i} - x_{i} b_{0} - b_{1}x_{i}^2 \right) \\
&= \left( -2\right) \left( \Sigma x_{i} y_{i} - \Sigma x_{i} b_{0} - \Sigma b_{1}x_{i}^2 \right) \\
\end{align*}\]
(my) STAT 184 Philosophy
- “less-volume, more creativity”
- A few simple tools can be combined in powerful ways
- Individually these tools are introduced as “data moves”
- The complexity comes from combining these simple tools in order to achieve our specific purposes
tidyverse
sub-language accomplishes this purpose within an ecosystem predicated upon so-called “Tidy” data.
Tidy Data
- “Neat” is not the same as “Tidy”
- Tidy data are organized according to two simple rules:
- The rows–called cases or observational units–each refer to a specific, unique, and similar sort of thing
- The columns, called variables, each have the same sort of value recorded for each case (i.e. row)
- Galton’s family data
- Are these data tidy?
- What is a case?
- What are the variables?
# package
require(mosaicData)
# intake data from `mosaicData` package
data("Galton")
head(Galton, 10)
tidyverse
command chains
- Each link in the chain is a “data verb” or “data move” with its arguments
- The very first link is typically a data table.
- Links are connected by the pipe:
%>%
- Often, but not always, you will store the result of the chain in a named object
- This is done with the assignment operator,
<-
- New line for each link
- Note that
%>%
is at the end of each line. Except
Hazels <-
is an assignment
- Last line has no
%>%
(otherwise R thinks there’s more)
# package
require(DataComputing)
# intake data
data("BabyNames")
# a command chain
Hazels <-
BabyNames %>%
filter(grepl("Hazel", name)) %>%
group_by(year) %>%
summarise(total = sum(count))
Parts of speech
- Data set
- function
- argument
- variables
- constants
Discussion question
Hazels <-
BabyNames %>%
filter(grepl("Hazel", name)) %>%
group_by(year) %>%
summarise(total = sum(count))
Just from the syntax, you should be able to tell which of the five different kinds of object each of these things is:
Hazels
BabyNames
filter
grepl
"Hazel"
name
group_by
year
summarise
total
sum
count
Small group discussion:
- Explain each of these common
tidyverse
functions:
- List 1–data joins & reshape:
left_join()
inner_join()
spread()
gather()
- List 2–data verbs:
mutate()
filter()
select()
arrange()
- List 3–more data verbs:
head()
& tail()
transmute()
rename()
sample_n()
summarise()
& group_by()
- List 4–summary functions:
glimpse()
str()
summary()
nrow()
& ncol()
names()
View()
- Are there functions that no one in the group understood?
Kinds of join
Different joins have different answers to these questions.
- What to do when there is no match between a left case and any right case?
- What to do when there are multiple matching cases in the right table for a case in the left table?
Popular join types:
left_join()
: joins matching rows from the right table to the left table
inner_join()
: only retain rows for which a match exists
IF no right cases match the left case…
left_join()
: Keep the left case and fill in the new variables (from the right table) with NA
inner_join()
: Discard the left case.
IF multiple right cases match the left case…
left_join()
and inner_join()
do the same thing:
left_join()
: Keep all combinations.
inner_join()
: Keep all combinations.
Other useful joins:
full_join()
Keep left case as well as unmatched right cases.
semi_join()
Discard left case corresponding to unmatched right case.
anti_join()
Keep the left case but discard any left case with a match in the right table
Reshaping data
gather()
stacks columns to convert from wide to narrow
spread()
unstacks columns to convert narrow to wide
require(dplyr)
# From http://stackoverflow.com/questions/1181060
Stocks <- tibble(
time = as.Date('2009-01-01') + 0:9,
X = rnorm(10, 0, 1),
Y = rnorm(10, 0, 2),
Z = rnorm(10, 0, 4)
)
# inspect data
Stocks
# gather/stack/melt--wide to narrow
StocksNarrow <-
Stocks %>%
gather(key = stock, value = price, X, Y, Z)
StocksNarrow
# spread/unstack/cast--narrow to wide
StocksWide <-
StocksNarrow %>%
spread(key = stock, value = price)
StocksWide
Three Important Concepts
- Data can be usefully organized into tables with “cases” and “variables.”
- In “tidy data” every case is the same sort of thing (e.g. a person, a car, a year, a country in a year)
- We sometimes even modify data in order to change what the cases represent in order to better represent a point.
- Data graphics and “glyph-ready” data
- each case corresponds to a “glyph” (mark) on the graph
- each variable to a graphical attribute of that glyph such as x- or y-position, color, size, length, shape, etc.
- same is true for more technical tools (e.g., models)
- When data are not yet in glyph-ready form, you can transform (i.e. wrangle) them into glyph-ready form.
- Such transformations are accomplished by performing one or more of a small set of basic operations on data tables
- This is the work of data “verbs”
Grammar of graphics
- the framework underpinning
ggplot2
intends to implement priniciples and philosophy set in Wilkonson’s 2005 book The Grammer of Graphics (2nd Ed.)
- using tidy data, each case corresponds to a glpyh or mark on the graph.
Anatomy of a data visualization
- Frame
- Glyph
- Aesthetic
- Scale
- Guide (legend)
- Facet
SAT Scores & Student Spending by State in the US
require(mdsr)
data("SAT_2010")
# 2010 SAT Scores grouped by participation rate
SAT_2010 <-
SAT_2010 %>%
mutate(SAT_rate = cut(sat_pct, breaks = c(0, 30, 60, 100),
labels = c("low", "medium", "high")))
# initialize scatter plot
g <-
SAT_2010 %>%
ggplot(aes(x = expenditure, y = math)) +
geom_point() +
geom_smooth(method = "lm", se = 0) +
xlab("Average expenditure per student ($1000)") +
ylab("Average score on math SAT")
# base plot showing SAT Math vs Student expenditure
g

# color scatter plot by SAT_rate
g +
aes(color = SAT_rate)

Some Graphics Components
glyph
The basic graphical unit that represents one case. Other terms used include mark and symbol.
aesthetic
- a visual property of a glyph such as position, size, shape, color, etc.
- may be mapped based on data values:
sex -> color
- may be set to particular non-data related values:
color is black
scale
- A mapping that translates data values into aesthetics.
- example: male -> blue; female -> pink
frame
- The position scale describing how data are mapped to x and y
guide
- An indication for the human viewer of the scale. This allows the viewer to translate aesthetics back into data values.
- Examples: x- and y-axes, various sorts of legends
Facets
# facet by SAT participation rate
g +
facet_wrap( ~ SAT_rate)

Layers
Medicare costs in Pennsylvania among other states
require(mdsr)
data("MedicareCharges", package = "mdsr") # from mdsr, not DataComputing
# Pennsylvania medicare charges
ChargesPA <-
MedicareCharges %>%
filter(stateProvider == "PA")
# Plot Pennsylvania data
p <-
ChargesPA %>%
ggplot(aes(x = reorder(drg, mean_charge), y = mean_charge)) +
geom_bar(fill = "gray", stat = "identity") + # stat = "identity" ==> value dictates bar height
ylab("Statewide Average Charges ($)") +
xlab("Medical Procedure (DRG)") +
theme(axis.text.x = element_text(angle = 90, hjust = 1))
p

# add layer to show other states for reference
p +
geom_point(data = MedicareCharges, size = 1, alpha = 0.3)

Fivethirtyeight reproduction (MDSR p. 50)
MDSR Reproduction
require(mdsr)
require(Hmisc)
BabynamesDist <- make_babynames_dist() # from mdsr
Joseph <- BabynamesDist %>%
filter(name == "Joseph" & sex == "M")
# constructing the base plot
name_plot <-
Joseph %>%
ggplot(aes(x = year)) +
geom_bar(stat = "identity", aes(y = count_thousands * alive_prob),
fill = "#b2d7e9", color = "white") +
geom_line(aes(y = count_thousands), size = 2) +
ylab("Number of People (thousands)") +
xlab(NULL)
# base plot
name_plot

median_yob <- wtd.quantile(x = Joseph$year, weights = Joseph$est_alive_today, probs = 0.5)
median_yob
50%
1975
- note the clever use of
ifelse
to create a new histogram with one non-zero bar at median_yob
- add titles
- add text labels (improve fonts)
- add curved arrow
- add improvements
- better fonts
- better titles
- better frame
- etc
name_plot <-
name_plot +
geom_bar(stat = "identity", color = "white", fill = "#008fd5",
aes(y = ifelse(year == median_yob, est_alive_today / 1000, 0)))
# Figure 3.22: Josephs
name_plot +
ggtitle(label = "Age Distribution of American Boys Named Joseph", subtitle = "By year of birth") +
geom_text(x = 1935, y = 40, size = 3.5, family = "mono", label = "Number of Josephs \n born each year") +
geom_text(x = 1915, y = 13, size = 3.5, family = "mono", color = "#008fd5",
label = "Number of Josephs \n born each year \n estimated to be alive \n on Jan. 1, 2014") +
geom_text(x = 2003, y = 40, size = 3.5, family = "sans", color = "darkgray",
label = "The median\nliving Joseph\nis 37 years old.") +
geom_curve(x = 1995, xend = 1974, y = 40, yend = 24,
arrow = arrow(length = unit(0.3, "cm")), curvature = 0.5) +
ylim(0, 42) +
theme_fivethirtyeight()

NA
Three Important Concepts
- Data can be usefully organized into tables with “cases” and “variables.”
- In “tidy data” every case is the same sort of thing (e.g. a person, a car, a year, a country in a year)
- We sometimes even modify data in order to change what the cases represent in order to better represent a point.
- Data graphics and “glyph-ready” data
- each case corresponds to a “glyph” (mark) on the graph
- each variable to a graphical attribute of that glyph such as x- or y-position, color, size, length, shape, etc.
- same is true for more technical tools (e.g., models)
- When data are not yet in glyph-ready form, you can transform (i.e. wrangle) them into glyph-ready form.
- Such transformations are accomplished by performing one or more of a small set of basic operations on data tables
- This is the work of data “verbs”
LS0tCnRpdGxlOiAiU1RBVCAxODQgUmV2aWV3IgphdXRob3I6ICJNYXR0aGV3IEJlY2ttYW4iCm91dHB1dDogCiAgc2xpZHlfcHJlc2VudGF0aW9uOiBkZWZhdWx0CiAgaHRtbF9ub3RlYm9vazogZGVmYXVsdAotLS0KCmBgYHtyIGluY2x1ZGU9RkFMU0V9CiMgRnJvbnRtYXR0ZXIKcm0obGlzdCA9IGxzKCkpICAjIGNsZWFuLXVwCgojIHBhY2thZ2VzCmxpYnJhcnkoYmFieW5hbWVzKQpsaWJyYXJ5KERhdGFDb21wdXRpbmcpCmxpYnJhcnkoZ2d0aGVtZXMpCmxpYnJhcnkoSG1pc2MpCmxpYnJhcnkobWRzcikKbGlicmFyeShtb3NhaWMpCmxpYnJhcnkodGlkeXZlcnNlKQoKIyBpbnB1dHMgJiBvdXRwdXRzCgojIyBgR2FsdG9uYCAgICAgZnJvbSBtb3NhaWNEYXRhIHBhY2thZ2UgCiMjIGBCYWJ5TmFtZXNgICBmcm9tIERhdGFDb21wdXRpbmcgcGFja2FnZQojIyBgU3RvY2tzYCAgICAgc2ltdWxhdGVkIGRhdGEKIyMgYFNBVF8yMDEwYCAgIGZyb20gbWRzciBwYWNrYWdlCiMjIGBiYWJ5bmFtZXNgICBmcm9tIGJhYnluYW1lcyBwYWNrYWdlCiMjIGBNZWRpY2FyZUNoYXJnZXNgIGZyb20gbWRzcgpgYGAKCgojIyBBZ2VuZGEKCi0gcmV2aXNpdCByZXByb2R1Y2libGUgd29ya2Zsb3cKLSBzb21lIHJldmlldyBvZiBTVEFUIDE4NCB0b3BpY3MKCiMjIyMgSG9tZXdvcmsgCgotIChsYXRlKSBHZW5lcmljIFIgTm90ZWJvb2sKLSAobGF0ZSkgR2l0SHViIFN0YXJ0dXAKLSAoZnJpZGF5KSBQcm9ncmFtbWluZyBOb3RlYm9va3M6IE1EU1IgQ2hhcHRlciAwNAotIChzdW5kYXkpIFByb2dyYW1taW5nIE5vdGVib29rczogTURTUiBDaGFwdGVyIDAzCi0gKG5leHQgd2VlaykgTURTUiBDaGFwIDMgRXhlcmNpc2VzCi0gKG5leHQgd2VlaykgUHJvZ3JhbW1pbmcgTm90ZWJvb2tzOiBNRFNSIENoYXB0ZXIgMDUKCiMjIFNUQVQgMzgwIHdvcmtmbG93CgotIFJlcHJvZHVjaWJsZSBSZXNlYXJjaAogICAgLSBHaXQoSHViKSBzb3VyY2UgY29udHJvbCBiYXNpY3MKICAgIC0gUlN0dWRpbyBJREUgKFIsIFJtZCwgR2l0KQoKCiMjIEdpdCAvIEdpdEh1YgoKLSBHaXRIdWIncyBJbnRybzogPGh0dHBzOi8vZ3VpZGVzLmdpdGh1Yi5jb20vYWN0aXZpdGllcy9oZWxsby13b3JsZC8+Ci0gIkdpdEh1YiBpcyBhIGNvZGUgaG9zdGluZyBwbGF0Zm9ybSBmb3IgdmVyc2lvbiBjb250cm9sIGFuZCBjb2xsYWJvcmF0aW9uLiBJdCBsZXRzIHlvdSBhbmQgb3RoZXJzIHdvcmsgdG9nZXRoZXIgb24gcHJvamVjdHMgZnJvbSBhbnl3aGVyZS4iIAotICoqUmVwb3NpdG9yaWVzKiogYXJlIHVzZWQgdG8gb3JnYW5pemUgZWFjaCBwcm9qZWN0CiAgICAtIFRoZXNlIGNhbiBjb250YWluIGRvY3VtZW50cywgaW1hZ2VzLCBmb2xkZXJzLCBjb2RlLCBkYXRhLCAuLi4gYmFzaWNhbGx5IGV2ZXJ5dGhpbmcgeW91IG5lZWQgZm9yIHlvdXIgcHJvamVjdCAKICAgIC0gTGFyZ2VyIGZpbGVzICg+IDEwLTE1IE1CKSBuZWVkIHNvbWUgc3BlY2lhbCBoYW5kbGluZywgYnV0IHVzdWFsbHkgbm90IGEgYmlnIGRlYWwKICAgIC0gWW91J2xsIHNvb24gbGluayBlYWNoICoqR2l0SHViIFJlcG9zaXRvcnkqKiB0byBhbiAqKlJTdHVkaW8gUHJvamVjdCoqIHRvIHN0cmVhbWxpbmUgdGhlIHdvcmtmbG93CiAgICAtIERvbid0IHB1dCByZXBvc2l0b3JpZXMgaW5zaWRlIG90aGVyIHJlcG9zaXRvcmllcwotIE1vc3Qgb2YgeW91ciB3b3JrZmxvdyBpcyB1bmNoYW5nZWQKICAgIC0gQXMgZmFyIGFzIHlvdXIgY29tcHV0ZXIgaXMgY29uY2VybmVkLCB0aGUgcmVwb3NpdG9yeSB3b3JrcyBqdXN0IGxpa2UgYW55IG90aGVyIGRpcmVjdG9yeSAoaS5lLiBmb2xkZXIpCiAgICAtIFlvdSBlZGl0IGZpbGVzLCBzYXZlIGNoYW5nZXMsIGV0YwoKIVtEci4gQmVja21hbidzIERpcmVjdG9yeSB0byBPcmdhbml6ZSBHaXRIdWIgUmVwb3NpdG9yaWVzXShHaXRIdWIgRGlyZWN0b3J5LnBuZykKCgojIyBHaXQgLyBHaXRIdWIKCi0gRmlyc3QgbmV3IHBhcnQ6ICgqKmNvbW1pdCoqKSBjaGFuZ2VzCiAgICAtIGlkZWFsbHksIGVhY2ggY29tbWl0IHNob3VsZCBlbmNvbXBhc3MgKm9uZSBtZWFuaW5nZnVsIG1vZGlmaWNhdGlvbiogCiAgICAtIGNyZWF0ZXMgYSBwZXJtYW5lbnQgc25hcHNob3Qgb2YgdGhlIHJlcG9zaXRvcnkKICAgIC0geW91IGNhbiByZXZpc2l0IHRoZXNlIHNuYXBzaG90cyBhdCBhbnkgdGltZS4uLiAKLSBTZWNvbmQgbmV3IHBhcnQ6ICgqKnB1c2gvcHVsbCoqKSB0byByZW1vdGUKICAgIC0gR2l0SHViIHN0b3JlcyB0aGUgc3RhdGUgb2YgeW91ciByZXBvc2l0b3J5IGluIHRoZSBjbG91ZAogICAgLSBXaGVuIHlvdSAqcHVzaCosIHlvdSB1cGRhdGUgdGhlIHJlbW90ZSB2ZXJzaW9uIAogICAgLSBBbnlvbmUgd2l0aCBhY2Nlc3MgdG8geW91ciBHaXRIdWIgcmVwb3NpdG9yeSBjYW4gKnB1bGwqIHRoZSByZW1vdGUgdmVyc2lvbiBhbmQgd29yayB3aXRoIGl0CiAgICAgICAgLSBUaGlzIG1pZ2h0IGJlIHlvdSwgdXNpbmcgYSBkaWZmZXJlbnQgY29tcHV0ZXIKICAgICAgICAtIEl0IG1pZ2h0IGJlIGEgY29sbGFib3JhdG9yIAogICAgICAgIC0gSXQgbWlnaHQgYmUgYSBwcm9mZXNzb3Igb3IgVEEKICAgICAgICAtIElmIHRoZSByZXBvIGlzIG1hZGUgcHVibGljLCBpdCBtaWdodCBiZSBhIGNvbXBsZXRlIHN0cmFuZ2VyIQogICAgLSBUaGUgY29sbGFib3JhdG9yIGNhbiB0aGVuIGNvbW1pdCBjaGFuZ2VzIGFuZCBwdXNoIHRoZW0gdG8gdGhlIHJlbW90ZSBhcyB3ZWxsIAogICAgICAgIC0gZG9uJ3Qgd29ycnksIHRoZXJlIGFyZSBzYWZlZ3VhcmRzIGluIHBsYWNlIGJhc2VkIG9uIHVzZXIgcGVybWlzc2lvbnMKCgohW0dpdCBTY2hlbWF0aWM6IGh0dHA6Ly93d3cudHNiYWtrZXIubmwvZ2l0Lmh0bWxdKGdpdHN0YWdlcy5qcGcpCgojIyBHaXQgLyBHaXRIdWIKCi0gT25jZSBjb25maWd1cmVkLCBuZWFybHkgYWxsIG9mIHRoZSBhY3Rpb24gY2FuIGhhcHBlbiBpbiBSU3R1ZGlvCi0gQSAiR2l0IiB0YWIgd2lsbCBhcHBlYXIgaW4gUlN0dWRpbwotIERpZmYsIENvbW1pdCwgUHVsbCwgUHVzaCBhcmUgbW9zdCBjb21tb24gYWN0aW9ucwoKCiFbXShHaXRIdWIgRGlyZWN0b3J5IFJTdHVkaW8ucG5nKQoKCgoKIyMgTWFya2Rvd24gLyBSIE1hcmtkb3duCgotIEh1bWFuLXJlYWRhYmxlIHN5bnRheCBieSBkZXNpZ24KLSBDYW4gImtuaXQiIChvciBwcmV2aWV3KSBzYW1lIC5SbWQgdG8gSFRNTCAob3IgUERGIG9yIE1TIFdvcmQgd2l0aCBzb21lIGNvbmZpZ3VyYXRpb24pCi0gQ2FuIHByb2R1Y2UgYm90aCBub3RlYm9vaywgc2xpZGVzLCBkb2N1bWVudCwgd2VicGFnZSwgZXRjIGFzIG91dHB1dC4KLSAqKlJlZ2FyZGxlc3MqKiBvZiBpbnRlbmRlZCBvdXRwdXQsIFJtZCBkb2N1bWVudHMgZ2VuZXJhbGx5IHJlcXVpcmUgdHdvIHBhcnRzCiAgICAtICJ5YW1sIiBoZWFkZXIgYXQgdGhlIHRvcCAoZGVzaWduYXRlZCBieSBgLS0tYCBiZWZvcmUvYWZ0ZXIpIGluY2x1ZGVzIHNvbWUgZG9jdW1lbnQgY29udHJvbHMKICAgICAgICAtIHRpdGxlCiAgICAgICAgLSBhdXRob3IKICAgICAgICAtIGRhdGUKICAgICAgICAtIG91dHB1dAogICAgICAgIC0gKGV0YykKICAgIC0gYm9keSBvZiB0aGUgZG9jdW1lbnQgaW5jbHVkaW5nIGNvbXBvbmVudHMgc3VjaCBhczogIAogICAgICAgIC0gTWFya2Rvd24gc3ludGF4IChsaWtlIGhhc2h0YWcgaGVhZGVycykKICAgICAgICAtIE5hcnJhdGl2ZSB0ZXh0CiAgICAgICAgLSBMaXN0cyAoYnVsbGV0cyBvciBudW1iZXJzKQogICAgICAgIC0gQ29kZSAiY2h1bmtzIiAoUiwgcHl0aG9uLCBTUUwsIFN0YW4sIGV0YyBlbWJlZGRlZCBhbW9uZyB0aGUgbmFycmF0aXZlIG9mIHRoZSBkb2N1bWVudCkKICAgICAgICAtIFVSTHMKICAgICAgICAtIEltYWdlcwogICAgICAgIC0gVGFibGVzCiAgICAgICAgLSBhbmQgbXVjaCBtb3JlLi4uCgoKIyMgV2h5IFJNYXJrZG93bj8KCiMjIyMgUk1hcmtkb3duIGxldHMgdXMgc2VwYXJhdGUgY29udGVudCBmcm9tIGZvcm1hdHRpbmcKCi0gQWx0ZXJuYXRpdmUgdG8gV1lTSVdZRydzIGxpa2UgTVMgV29yZCAmIEdvb2dsZSBEb2NzIAotIEVhc3kgdG8gY29uZmlndXJlIGhlYWRpbmdzLCBsaXN0cywgVE9DLCBmaWd1cmVzLCBjYXB0aW9ucywgbGlua3MsIGltYWdlcywgZXRjCi0gQ2hhbmdlIGZvcm1hdHRpbmcgZ2xvYmFsbHkgd2l0aCBhIGNzcyAoY2FzY2FkaW5nIHN0eWxlIHNoZWV0KQotIEdvb2QtbG9va2luZyB0YWJsZXMgYXJlIGVhc3kKLSBUeXBlc2V0IG5pY2UtbG9va2luZyBtYXRoZW1hdGljcyB1c2luZyBMYVRlWCAoYW5kIHNvbWUgcHJldmlldykKCiMjIyMgU1RBVCA1MDEgZXhjZXJwdCAoaW5saW5lIG1hdGgpLi4uCgpIZXJlJ3MgdGhlIG1vZGVsOiAKCiRsb2coXGZyYWN7XGhhdHtwfV9pfXsxLVxoYXR7cH1faX0pID0gMy4zMDkgLSAwLjI4OChkaXN0X2kpJAoKd2hlcmUgJFxoYXR7cH1faSQgaXMgdGhlIHByb3BvcnRpb24gdGhhdCB2b3RlZCAiWWVzIiBmb3IgY29tbXVuaXR5ICppKi4KCgpTaW5jZSB0aGUgcmVsYXRpb25zaGlwIG9uIGEgbG9nYXJpdGhtaWMgc2NhbGUgaXMgaGFyZCB0byBpbnRlcnByZXQsIHdlIGJhY2sgdHJhbnNmb3JtIGJlZm9yZSBpbnRlcnByZXRpbmcgY29lZmZpY2llbnRzLiAKCk5vdGU6IElmICRlXntcYmV0YV8xfSA9IDEkLCB0aGVuIGl0IG1lYW5zIHRoZSBvZGRzIGFyZSAxOjEgd2hpY2ggdHJhbnNsYXRlcyB0byBhIDUwLTUwIGNoYW5jZSBhbmQgbWVhbnMgdGhlcmUgd291bGQgYmUgbm8gcmVsYXRpb25zaGlwIGJldHdlZW4gdGhlIGV4cGxhbmF0b3J5IHZhcmlhYmxlIGFuZCB0aGUgb2RkcyBvZiAic3VjY2VzcyIgKGhvd2V2ZXIgdGhhdCdzIGRlZmluZWQgaW4gdGhlIGNvbnRleHQgb2YgdGhlIHN0dWR5KS4gIAoKIyMjIyBTVEFUIDUwMSBleGNlcnB0IChhbGlnbmVkIHRvIGA9YCBzaWduKS4uLgoKXGJlZ2lue2FsaWduKn0KClxtYXRoaXR7U1NFfSAmPSBcU2lnbWFfe2l9IFxsZWZ0KCB5X3tpfSAtIGJfezB9IC0gYl97MX14X3tpfSBccmlnaHQpXjIgXFwKClxcCgpcZnJhY3tccGFydGlhbCBcbGVmdCggU1NFIFxyaWdodCl9e1xwYXJ0aWFsIGJfezB9fSAmPSBcU2lnbWFfe2l9IFxsZWZ0KCB5X3tpfSAtIGJfezB9IC0gYl97MX14X3tpfSBccmlnaHQpXjIgXFwKICY9IFxsZWZ0KCAtMiBccmlnaHQpIFxTaWdtYV97aX0gXGxlZnQoIHlfe2l9IC0gYl97MH0gLSBiX3sxfXhfe2l9IFxyaWdodCkgXFwKICY9IFxsZWZ0KCAtMiBccmlnaHQpIFxsZWZ0KCBcU2lnbWEgeV97aX0gLSBcU2lnbWEgYl97MH0gLSBcU2lnbWEgYl97MX14X3tpfSBccmlnaHQpIFxcCgpcXAoKXGZyYWN7XHBhcnRpYWwgXGxlZnQoIFNTRSBccmlnaHQpfXtccGFydGlhbCBiX3sxfX0gJj0gXFNpZ21hX3tpfSBcbGVmdCggeV97aX0gLSBiX3swfSAtIGJfezF9eF97aX0gXHJpZ2h0KV4yIFxcCiAmPSBcU2lnbWFfe2l9IFxsZWZ0KCAtMnhfe2l9IFxyaWdodCkgXGxlZnQoIHlfe2l9IC0gYl97MH0gLSBiX3sxfXhfe2l9IFxyaWdodCkgXFwKICY9IFxsZWZ0KCAtMlxyaWdodCkgXFNpZ21hX3tpfSBcbGVmdCggeF97aX0geV97aX0gLSB4X3tpfSBiX3swfSAtIGJfezF9eF97aX1eMiBccmlnaHQpIFxcCiAmPSBcbGVmdCggLTJccmlnaHQpIFxsZWZ0KCBcU2lnbWEgeF97aX0geV97aX0gLSBcU2lnbWEgeF97aX0gYl97MH0gLSBcU2lnbWEgYl97MX14X3tpfV4yIFxyaWdodCkgXFwKClxlbmR7YWxpZ24qfQoKCiMjIChteSkgU1RBVCAxODQgUGhpbG9zb3BoeQoKLSAibGVzcy12b2x1bWUsIG1vcmUgY3JlYXRpdml0eSIgIAotIEEgZmV3IHNpbXBsZSB0b29scyBjYW4gYmUgY29tYmluZWQgaW4gcG93ZXJmdWwgd2F5cwotIEluZGl2aWR1YWxseSB0aGVzZSB0b29scyBhcmUgaW50cm9kdWNlZCBhcyAiZGF0YSBtb3ZlcyIgCi0gVGhlIGNvbXBsZXhpdHkgY29tZXMgZnJvbSBjb21iaW5pbmcgdGhlc2Ugc2ltcGxlIHRvb2xzIGluIG9yZGVyIHRvIGFjaGlldmUgb3VyIHNwZWNpZmljIHB1cnBvc2VzCi0gYHRpZHl2ZXJzZWAgc3ViLWxhbmd1YWdlIGFjY29tcGxpc2hlcyB0aGlzIHB1cnBvc2Ugd2l0aGluIGFuIGVjb3N5c3RlbSBwcmVkaWNhdGVkIHVwb24gc28tY2FsbGVkICJUaWR5IiBkYXRhLgoKSW5kaXZpZHVhbCBsZWdvIGJyaWNrcyBhcmUgc2ltcGxlLl5bU291cmNlIDogIkxlZ28gQ29sb3IgQnJpY2tzIiBieSBBbGFuIENoaWEgLSBMZWdvIENvbG9yIEJyaWNrcy4gTGljZW5zZWQgdW5kZXIgQ0MgQlktU0EgMi4wIHZpYSBbV2lraW1lZGlhIENvbW1vbnNdKGh0dHA6Ly9jb21tb25zLndpa2ltZWRpYS5vcmcvd2lraS9GaWxlOkxlZ29fQ29sb3JfQnJpY2tzLmpwZyNtZWRpYXZpZXdlci9GaWxlOkxlZ29fQ29sb3JfQnJpY2tzLmpwZyldICB8IEEgY29tcGxleCBtb2RlbCBtYWRlIG9mIGxlZ28gYnJpY2tzIF5bU291cmNlOiAqVHJhZmFsZ2FyIExlZ29sYW5kIDIwMDMqIGJ5IEthaWhzdSBUYWkgLSBLYWloc3UgVGFpLiBMaWNlbnNlZCB1bmRlciBDQyBCWS1TQSAzLjAgdmlhIFtXaWtpbWVkaWEgQ29tbW9uc10oaHR0cDovL2NvbW1vbnMud2lraW1lZGlhLm9yZy93aWtpL0ZpbGU6VHJhZmFsZ2FyX0xlZ29sYW5kXzIwMDMuanBnI21lZGlhdmlld2VyL0ZpbGU6VHJhZmFsZ2FyX0xlZ29sYW5kXzIwMDMuanBnKV18Ci0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tIHwgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0gIHwKIVtCcmlja3NdKExlZ29fQ29sb3JfQnJpY2tzLmpwZyl8ICFbVHJhZmFsZ2FyIExlZ29sYW5kXShUcmFmYWxnYXJfTGVnb2xhbmRfMjAwMy5qcGcpIHwKCgojIyBUaWR5IERhdGEKCi0gIk5lYXQiIGlzIG5vdCB0aGUgc2FtZSBhcyAiVGlkeSIKLSAqVGlkeSBkYXRhKiBhcmUgb3JnYW5pemVkIGFjY29yZGluZyB0byB0d28gc2ltcGxlIHJ1bGVzOiAKICAgIDEuIFRoZSByb3dzLS1jYWxsZWQgKmNhc2VzKiBvciBvYnNlcnZhdGlvbmFsIHVuaXRzLS1lYWNoIHJlZmVyIHRvIGEgc3BlY2lmaWMsIHVuaXF1ZSwgYW5kIHNpbWlsYXIgc29ydCBvZiB0aGluZwogICAgMi4gVGhlIGNvbHVtbnMsIGNhbGxlZCAqdmFyaWFibGVzKiwgZWFjaCBoYXZlIHRoZSBzYW1lIHNvcnQgb2YgdmFsdWUgcmVjb3JkZWQgZm9yIGVhY2ggY2FzZSAoaS5lLiByb3cpCi0gR2FsdG9uJ3MgZmFtaWx5IGRhdGEKICAgIC0gQXJlIHRoZXNlIGRhdGEgdGlkeT8KICAgIC0gV2hhdCBpcyBhIGNhc2U/CiAgICAtIFdoYXQgYXJlIHRoZSB2YXJpYWJsZXM/CgohW0EgcGFnZSBmcm9tIEZyYW5jaXMgR2FsdG9uJ3Mgbm90ZWJvb2suXShnYWx0b24tbm90ZWJvb2suanBnKQoKCmBgYHtyIGV2YWw9RkFMU0UsIGVjaG89VFJVRX0KIyBwYWNrYWdlCnJlcXVpcmUobW9zYWljRGF0YSkgIAoKIyBpbnRha2UgZGF0YSBmcm9tIGBtb3NhaWNEYXRhYCBwYWNrYWdlCmRhdGEoIkdhbHRvbiIpCgpoZWFkKEdhbHRvbiwgMTApCmBgYAoKIyMgYHRpZHl2ZXJzZWAgY29tbWFuZCBjaGFpbnMKCi0gRWFjaCBsaW5rIGluIHRoZSBjaGFpbiBpcyBhICJkYXRhIHZlcmIiIG9yICJkYXRhIG1vdmUiICB3aXRoIGl0cyBhcmd1bWVudHMKICAgIC0gVGhlIHZlcnkgZmlyc3QgbGluayBpcyB0eXBpY2FsbHkgYSBkYXRhIHRhYmxlLgogICAgLSBMaW5rcyBhcmUgY29ubmVjdGVkIGJ5IHRoZSBwaXBlOiBgJT4lYAotIE9mdGVuLCBidXQgbm90IGFsd2F5cywgeW91IHdpbGwgc3RvcmUgdGhlIHJlc3VsdCBvZiB0aGUgY2hhaW4gaW4gYSBuYW1lZCBvYmplY3QKICAgIC0gVGhpcyBpcyBkb25lIHdpdGggdGhlICphc3NpZ25tZW50IG9wZXJhdG9yKiwgYDwtYAotIE5ldyBsaW5lIGZvciBlYWNoIGxpbmsKLSBOb3RlIHRoYXQgYCU+JWAgaXMgYXQgdGhlIGVuZCBvZiBlYWNoIGxpbmUuICAqKkV4Y2VwdCoqCiAgICAtIGBIYXplbHMgPC1gIGlzIGFuIGFzc2lnbm1lbnQKICAgIC0gTGFzdCBsaW5lIGhhcyBubyBgJT4lYCAob3RoZXJ3aXNlIFIgdGhpbmtzIHRoZXJlJ3MgbW9yZSkKCgpgYGB7cn0KIyBwYWNrYWdlCnJlcXVpcmUoRGF0YUNvbXB1dGluZykKCiMgaW50YWtlIGRhdGEKZGF0YSgiQmFieU5hbWVzIikKCiMgYSBjb21tYW5kIGNoYWluCkhhemVscyA8LSAKICBCYWJ5TmFtZXMgJT4lCiAgZmlsdGVyKGdyZXBsKCJIYXplbCIsIG5hbWUpKSAlPiUKICBncm91cF9ieSh5ZWFyKSAlPiUKICBzdW1tYXJpc2UodG90YWwgPSBzdW0oY291bnQpKQpgYGAKCiMjIFBhcnRzIG9mIHNwZWVjaAoKLSBEYXRhIHNldAotIGZ1bmN0aW9uCi0gYXJndW1lbnQKLSB2YXJpYWJsZXMKLSBjb25zdGFudHMKCiMjIyMgRGlzY3Vzc2lvbiBxdWVzdGlvbgoKYGBge3IgZXZhbD1GQUxTRX0KSGF6ZWxzIDwtIAogIEJhYnlOYW1lcyAlPiUKICBmaWx0ZXIoZ3JlcGwoIkhhemVsIiwgbmFtZSkpICU+JQogIGdyb3VwX2J5KHllYXIpICU+JQogIHN1bW1hcmlzZSh0b3RhbCA9IHN1bShjb3VudCkpCmBgYAoKSnVzdCBmcm9tIHRoZSBzeW50YXgsIHlvdSBzaG91bGQgYmUgYWJsZSB0byB0ZWxsIHdoaWNoIG9mIHRoZSBmaXZlIGRpZmZlcmVudCBraW5kcyBvZiBvYmplY3QgZWFjaCBvZiB0aGVzZSB0aGluZ3MgaXM6IAoKLSBgSGF6ZWxzYCAKLSBgQmFieU5hbWVzYCAKLSBgZmlsdGVyYCAKLSBgZ3JlcGxgIAotIGAiSGF6ZWwiYCAKLSBgbmFtZWAgCi0gYGdyb3VwX2J5YCAKLSBgeWVhcmAgCi0gYHN1bW1hcmlzZWAgCi0gYHRvdGFsYCAKLSBgc3VtYCAKLSBgY291bnRgCgoKIyMgU21hbGwgZ3JvdXAgZGlzY3Vzc2lvbjogCgotIEV4cGxhaW4gZWFjaCBvZiB0aGVzZSBjb21tb24gYHRpZHl2ZXJzZWAgZnVuY3Rpb25zOgogICAgLSAqKkxpc3QgMS0tZGF0YSBqb2lucyAmIHJlc2hhcGU6KioKICAgICAgICAtIGBsZWZ0X2pvaW4oKWAKICAgICAgICAtIGBpbm5lcl9qb2luKClgCiAgICAgICAgLSBgc3ByZWFkKClgCiAgICAgICAgLSBgZ2F0aGVyKClgCiAgICAtICoqTGlzdCAyLS1kYXRhIHZlcmJzOioqCiAgICAgICAgLSBgbXV0YXRlKClgCiAgICAgICAgLSBgZmlsdGVyKClgCiAgICAgICAgLSBgc2VsZWN0KClgCiAgICAgICAgLSBgYXJyYW5nZSgpYAogICAgLSAqKkxpc3QgMy0tbW9yZSBkYXRhIHZlcmJzOioqCiAgICAgICAgLSBgaGVhZCgpYCAmIGB0YWlsKClgCiAgICAgICAgLSBgdHJhbnNtdXRlKClgCiAgICAgICAgLSBgcmVuYW1lKClgCiAgICAgICAgLSBgc2FtcGxlX24oKWAKICAgICAgICAtIGBzdW1tYXJpc2UoKWAgJiBgZ3JvdXBfYnkoKWAKICAgIC0gKipMaXN0IDQtLXN1bW1hcnkgZnVuY3Rpb25zOioqCiAgICAgICAgLSBgZ2xpbXBzZSgpYAogICAgICAgIC0gYHN0cigpYAogICAgICAgIC0gYHN1bW1hcnkoKWAKICAgICAgICAtIGBucm93KClgICYgYG5jb2woKWAKICAgICAgICAtIGBuYW1lcygpYAogICAgICAgIC0gYFZpZXcoKWAKLSBBcmUgdGhlcmUgZnVuY3Rpb25zIHRoYXQgbm8gb25lIGluIHRoZSBncm91cCB1bmRlcnN0b29kPwoKCgojIyBLaW5kcyBvZiBqb2luCgoKRGlmZmVyZW50IGpvaW5zIGhhdmUgZGlmZmVyZW50IGFuc3dlcnMgdG8gdGhlc2UgcXVlc3Rpb25zLgoKKiBXaGF0IHRvIGRvIHdoZW4gdGhlcmUgaXMgKipubyBtYXRjaCoqIGJldHdlZW4gYSBsZWZ0IGNhc2UgYW5kIGFueSByaWdodCBjYXNlPwoqIFdoYXQgdG8gZG8gd2hlbiB0aGVyZSBhcmUgKiptdWx0aXBsZSBtYXRjaGluZyBjYXNlcyoqIGluIHRoZSByaWdodCB0YWJsZSBmb3IgYSBjYXNlIGluIHRoZSBsZWZ0IHRhYmxlPwoKClBvcHVsYXIgam9pbiB0eXBlczogCgotIGBsZWZ0X2pvaW4oKWA6IGpvaW5zIG1hdGNoaW5nIHJvd3MgZnJvbSB0aGUgKnJpZ2h0KiB0YWJsZSB0byB0aGUgKmxlZnQqIHRhYmxlCi0gYGlubmVyX2pvaW4oKWA6IG9ubHkgcmV0YWluIHJvd3MgZm9yIHdoaWNoIGEgbWF0Y2ggZXhpc3RzCgo8YnI+CgojIyMjIElGIG5vIHJpZ2h0IGNhc2VzIG1hdGNoIHRoZSBsZWZ0IGNhc2UuLi4KCi0gYGxlZnRfam9pbigpYDogS2VlcCB0aGUgbGVmdCBjYXNlIGFuZCBmaWxsIGluIHRoZSBuZXcgdmFyaWFibGVzIChmcm9tIHRoZSByaWdodCB0YWJsZSkgd2l0aCBgTkFgCi0gYGlubmVyX2pvaW4oKWA6IERpc2NhcmQgdGhlIGxlZnQgY2FzZS4KCjxicj4KCiMjIyMgSUYgbXVsdGlwbGUgcmlnaHQgY2FzZXMgbWF0Y2ggdGhlIGxlZnQgY2FzZS4uLgoKYGxlZnRfam9pbigpYCBhbmQgYGlubmVyX2pvaW4oKWAgZG8gdGhlIHNhbWUgdGhpbmc6CgoqIGBsZWZ0X2pvaW4oKWA6IEtlZXAgKiphbGwgY29tYmluYXRpb25zKiouCiogYGlubmVyX2pvaW4oKWA6IEtlZXAgKiphbGwgY29tYmluYXRpb25zKiouCgo8YnI+CgojIyMjIE90aGVyIHVzZWZ1bCBqb2luczoKCiogYGZ1bGxfam9pbigpYCBLZWVwIGxlZnQgY2FzZSBhcyB3ZWxsIGFzIHVubWF0Y2hlZCByaWdodCBjYXNlcy4KKiBgc2VtaV9qb2luKClgIERpc2NhcmQgbGVmdCBjYXNlIGNvcnJlc3BvbmRpbmcgdG8gdW5tYXRjaGVkIHJpZ2h0IGNhc2UuCiogYGFudGlfam9pbigpYCBLZWVwIHRoZSBsZWZ0IGNhc2UgYnV0IGRpc2NhcmQgYW55IGxlZnQgY2FzZSB3aXRoIGEgbWF0Y2ggaW4gdGhlIHJpZ2h0IHRhYmxlCgoKIyMgUmVzaGFwaW5nIGRhdGEKCi0gYGdhdGhlcigpYCBzdGFja3MgY29sdW1ucyB0byBjb252ZXJ0IGZyb20gd2lkZSB0byBuYXJyb3cKLSBgc3ByZWFkKClgIHVuc3RhY2tzIGNvbHVtbnMgdG8gY29udmVydCBuYXJyb3cgdG8gd2lkZQoKCmBgYHtyfQpyZXF1aXJlKGRwbHlyKQojIEZyb20gaHR0cDovL3N0YWNrb3ZlcmZsb3cuY29tL3F1ZXN0aW9ucy8xMTgxMDYwClN0b2NrcyA8LSB0aWJibGUoCiAgdGltZSA9IGFzLkRhdGUoJzIwMDktMDEtMDEnKSArIDA6OSwKICBYID0gcm5vcm0oMTAsIDAsIDEpLAogIFkgPSBybm9ybSgxMCwgMCwgMiksCiAgWiA9IHJub3JtKDEwLCAwLCA0KQopCgojIGluc3BlY3QgZGF0YQpTdG9ja3MKCiMgZ2F0aGVyL3N0YWNrL21lbHQtLXdpZGUgdG8gbmFycm93ClN0b2Nrc05hcnJvdyA8LSAKICBTdG9ja3MgJT4lIAogIGdhdGhlcihrZXkgPSBzdG9jaywgdmFsdWUgPSBwcmljZSwgWCwgWSwgWikgIAoKU3RvY2tzTmFycm93IAoKIyBzcHJlYWQvdW5zdGFjay9jYXN0LS1uYXJyb3cgdG8gd2lkZQpTdG9ja3NXaWRlIDwtIAogIFN0b2Nrc05hcnJvdyAlPiUgCiAgc3ByZWFkKGtleSA9IHN0b2NrLCB2YWx1ZSA9IHByaWNlKQoKU3RvY2tzV2lkZQpgYGAKCgojIyBUaHJlZSBJbXBvcnRhbnQgQ29uY2VwdHMgCgoxLiBEYXRhIGNhbiBiZSB1c2VmdWxseSBvcmdhbml6ZWQgaW50byB0YWJsZXMgd2l0aCAiY2FzZXMiIGFuZCAidmFyaWFibGVzLiIgIAogICAgLSBJbiAidGlkeSBkYXRhIiBldmVyeSBjYXNlIGlzIHRoZSBzYW1lIHNvcnQgb2YgdGhpbmcgKGUuZy4gYSBwZXJzb24sIGEgY2FyLCBhIHllYXIsIGEgY291bnRyeSBpbiBhIHllYXIpIAogICAgLSBXZSBzb21ldGltZXMgZXZlbiBtb2RpZnkgZGF0YSBpbiBvcmRlciB0byBjaGFuZ2Ugd2hhdCB0aGUgY2FzZXMgcmVwcmVzZW50IGluIG9yZGVyIHRvIGJldHRlciByZXByZXNlbnQgYSBwb2ludC4KCiMuIERhdGEgZ3JhcGhpY3MgYW5kICJnbHlwaC1yZWFkeSIgZGF0YQogICAgLSBlYWNoIGNhc2UgY29ycmVzcG9uZHMgdG8gYSAiZ2x5cGgiIChtYXJrKSBvbiB0aGUgZ3JhcGgKICAgIC0gZWFjaCB2YXJpYWJsZSB0byBhIGdyYXBoaWNhbCBhdHRyaWJ1dGUgb2YgdGhhdCBnbHlwaCBzdWNoIGFzIHgtIG9yIHktcG9zaXRpb24sIGNvbG9yLCBzaXplLCBsZW5ndGgsIHNoYXBlLCBldGMuIAogICAgLSBzYW1lIGlzIHRydWUgZm9yIG1vcmUgdGVjaG5pY2FsIHRvb2xzIChlLmcuLCBtb2RlbHMpIAoKIy4gV2hlbiBkYXRhIGFyZSBub3QgeWV0IGluIGdseXBoLXJlYWR5IGZvcm0sIHlvdSBjYW4gdHJhbnNmb3JtIChpLmUuIHdyYW5nbGUpIHRoZW0gaW50byBnbHlwaC1yZWFkeSBmb3JtLiAgCiAgICAtIFN1Y2ggdHJhbnNmb3JtYXRpb25zIGFyZSBhY2NvbXBsaXNoZWQgYnkgcGVyZm9ybWluZyBvbmUgb3IgbW9yZSBvZiBhIHNtYWxsIHNldCBvZiBiYXNpYyBvcGVyYXRpb25zIG9uIGRhdGEgdGFibGVzCiAgICAtIFRoaXMgaXMgdGhlIHdvcmsgb2YgZGF0YSAidmVyYnMiIAoKCgojIyBHcmFtbWFyIG9mIGdyYXBoaWNzCgotIHRoZSBmcmFtZXdvcmsgdW5kZXJwaW5uaW5nIGBnZ3Bsb3QyYCBpbnRlbmRzIHRvIGltcGxlbWVudCBwcmluaWNpcGxlcyBhbmQgcGhpbG9zb3BoeSBzZXQgaW4gV2lsa29uc29uJ3MgMjAwNSBib29rICpUaGUgR3JhbW1lciBvZiBHcmFwaGljcyAoMm5kIEVkLikqCi0gdXNpbmcgdGlkeSBkYXRhLCBlYWNoICpjYXNlKiBjb3JyZXNwb25kcyB0byBhICpnbHB5aCogb3IgbWFyayBvbiB0aGUgZ3JhcGguCgohW10oZ3JhbW1hckdyYXBoaWNzLnBuZykKCiMjIyMgQW5hdG9teSBvZiBhIGRhdGEgdmlzdWFsaXphdGlvbgoKLSBGcmFtZQotIEdseXBoCi0gQWVzdGhldGljCi0gU2NhbGUKLSBHdWlkZSAobGVnZW5kKQotIEZhY2V0CgoKIyMjIyBTQVQgU2NvcmVzICYgU3R1ZGVudCBTcGVuZGluZyBieSBTdGF0ZSBpbiB0aGUgVVMKCmBgYHtyfQpyZXF1aXJlKG1kc3IpCmRhdGEoIlNBVF8yMDEwIikKCiMgMjAxMCBTQVQgU2NvcmVzIGdyb3VwZWQgYnkgcGFydGljaXBhdGlvbiByYXRlClNBVF8yMDEwIDwtIAogIFNBVF8yMDEwICU+JQogIG11dGF0ZShTQVRfcmF0ZSA9IGN1dChzYXRfcGN0LCBicmVha3MgPSBjKDAsIDMwLCA2MCwgMTAwKSwgCiAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoImxvdyIsICJtZWRpdW0iLCAiaGlnaCIpKSkKCiMgaW5pdGlhbGl6ZSBzY2F0dGVyIHBsb3QKZyA8LSAKICBTQVRfMjAxMCAlPiUKICBnZ3Bsb3QoYWVzKHggPSBleHBlbmRpdHVyZSwgeSA9IG1hdGgpKSArIAogIGdlb21fcG9pbnQoKSArIAogIGdlb21fc21vb3RoKG1ldGhvZCA9ICJsbSIsIHNlID0gMCkgKyAKICB4bGFiKCJBdmVyYWdlIGV4cGVuZGl0dXJlIHBlciBzdHVkZW50ICgkMTAwMCkiKSArIAogIHlsYWIoIkF2ZXJhZ2Ugc2NvcmUgb24gbWF0aCBTQVQiKQoKIyBiYXNlIHBsb3Qgc2hvd2luZyBTQVQgTWF0aCB2cyBTdHVkZW50IGV4cGVuZGl0dXJlCmcKYGBgCgpgYGB7cn0KIyBjb2xvciBzY2F0dGVyIHBsb3QgYnkgU0FUX3JhdGUKZyArIAogIGFlcyhjb2xvciA9IFNBVF9yYXRlKQpgYGAKCiMjIFNvbWUgR3JhcGhpY3MgQ29tcG9uZW50cwoKIyMjIyAqKmdseXBoKioKVGhlIGJhc2ljIGdyYXBoaWNhbCB1bml0IHRoYXQgcmVwcmVzZW50cyBvbmUgY2FzZS4KT3RoZXIgdGVybXMgdXNlZCBpbmNsdWRlICptYXJrKiBhbmQgKnN5bWJvbCouIAoKIyMjIyAqKmFlc3RoZXRpYyoqCgoqIGEgdmlzdWFsIHByb3BlcnR5IG9mIGEgZ2x5cGggc3VjaCBhcyBwb3NpdGlvbiwgc2l6ZSwgc2hhcGUsIGNvbG9yLCBldGMuICAKKiBtYXkgYmUgKiptYXBwZWQqKiBiYXNlZCBvbiBkYXRhIHZhbHVlczogYHNleCAtPiBjb2xvcmAgCiogbWF5IGJlICoqc2V0KiogdG8gcGFydGljdWxhciBub24tZGF0YSByZWxhdGVkIHZhbHVlczogYGNvbG9yIGlzIGJsYWNrYAoKIyMjIyAqKnNjYWxlKioKCiogQSBtYXBwaW5nIHRoYXQgdHJhbnNsYXRlcyBkYXRhIHZhbHVlcyBpbnRvIGFlc3RoZXRpY3MuCiogZXhhbXBsZTogIG1hbGUgLT4gPGZvbnQgY29sb3I9ImJsdWUiPmJsdWU8L2ZvbnQ+OyBmZW1hbGUgLT4gPGZvbnQgY29sb3I9InBpbmsiPnBpbms8L2ZvbnQ+CgojIyMjICoqZnJhbWUqKgoKKiBUaGUgcG9zaXRpb24gc2NhbGUgZGVzY3JpYmluZyBob3cgZGF0YSBhcmUgbWFwcGVkIHRvIHggYW5kIHkKCiMjIyMgKipndWlkZSoqCgoqIEFuIGluZGljYXRpb24gZm9yIHRoZSBodW1hbiB2aWV3ZXIgb2YgdGhlIHNjYWxlLiAgVGhpcyBhbGxvd3MgdGhlIHZpZXdlciB0byB0cmFuc2xhdGUgYWVzdGhldGljcyBiYWNrIGludG8gZGF0YSB2YWx1ZXMuCiogRXhhbXBsZXM6ICB4LSBhbmQgeS1heGVzLCB2YXJpb3VzIHNvcnRzIG9mIGxlZ2VuZHMKCgoKCiMjIEZhY2V0cwoKYGBge3J9CiMgZmFjZXQgYnkgU0FUIHBhcnRpY2lwYXRpb24gcmF0ZQpnICsgCiAgZmFjZXRfd3JhcCggfiBTQVRfcmF0ZSkKYGBgCgoKCiMjIExheWVycyAKCiMjIyMgTWVkaWNhcmUgY29zdHMgaW4gUGVubnN5bHZhbmlhIGFtb25nIG90aGVyIHN0YXRlcwoKYGBge3J9CnJlcXVpcmUobWRzcikKZGF0YSgiTWVkaWNhcmVDaGFyZ2VzIiwgcGFja2FnZSA9ICJtZHNyIikgICAjIGZyb20gbWRzciwgbm90IERhdGFDb21wdXRpbmcKCiMgUGVubnN5bHZhbmlhIG1lZGljYXJlIGNoYXJnZXMKQ2hhcmdlc1BBIDwtIAogIE1lZGljYXJlQ2hhcmdlcyAlPiUKICBmaWx0ZXIoc3RhdGVQcm92aWRlciA9PSAiUEEiKQpgYGAKCmBgYHtyIGZpZy5oZWlnaHQ9MywgZmlnLndpZHRoPTh9CiMgUGxvdCBQZW5uc3lsdmFuaWEgZGF0YQpwIDwtIAogIENoYXJnZXNQQSAlPiUKICBnZ3Bsb3QoYWVzKHggPSByZW9yZGVyKGRyZywgbWVhbl9jaGFyZ2UpLCB5ID0gbWVhbl9jaGFyZ2UpKSArIAogIGdlb21fYmFyKGZpbGwgPSAiZ3JheSIsIHN0YXQgPSAiaWRlbnRpdHkiKSArICAgIyBzdGF0ID0gImlkZW50aXR5IiA9PT4gdmFsdWUgZGljdGF0ZXMgYmFyIGhlaWdodAogIHlsYWIoIlN0YXRld2lkZSBBdmVyYWdlIENoYXJnZXMgKCQpIikgKyAKICB4bGFiKCJNZWRpY2FsIFByb2NlZHVyZSAoRFJHKSIpICsgCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgaGp1c3QgPSAxKSkKcApgYGAKCgpgYGB7ciBmaWcuaGVpZ2h0PTMsIGZpZy53aWR0aD04fQojIGFkZCBsYXllciB0byBzaG93IG90aGVyIHN0YXRlcyBmb3IgcmVmZXJlbmNlCnAgKyAKICBnZW9tX3BvaW50KGRhdGEgPSBNZWRpY2FyZUNoYXJnZXMsIHNpemUgPSAxLCBhbHBoYSA9IDAuMykKYGBgCgoKIyMgRml2ZXRoaXJ0eWVpZ2h0IHJlcHJvZHVjdGlvbiAoTURTUiBwLiA1MCkKCiFbXShqb3NlcGhzRml2ZXRoaXJ0eWVpZ2h0LnBuZykKCiMjIE1EU1IgUmVwcm9kdWN0aW9uCgpgYGB7cn0KcmVxdWlyZShtZHNyKQpyZXF1aXJlKEhtaXNjKQoKQmFieW5hbWVzRGlzdCA8LSBtYWtlX2JhYnluYW1lc19kaXN0KCkgICMgZnJvbSBtZHNyCgpKb3NlcGggPC0gQmFieW5hbWVzRGlzdCAlPiUKICBmaWx0ZXIobmFtZSA9PSAiSm9zZXBoIiAmIHNleCA9PSAiTSIpCgojIGNvbnN0cnVjdGluZyB0aGUgYmFzZSBwbG90Cm5hbWVfcGxvdCA8LSAKICBKb3NlcGggJT4lCiAgZ2dwbG90KGFlcyh4ID0geWVhcikpICsgCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIGFlcyh5ID0gY291bnRfdGhvdXNhbmRzICogYWxpdmVfcHJvYiksIAogICAgICAgICAgIGZpbGwgPSAiI2IyZDdlOSIsIGNvbG9yID0gIndoaXRlIikgKyAKICBnZW9tX2xpbmUoYWVzKHkgPSBjb3VudF90aG91c2FuZHMpLCBzaXplID0gMikgKyAKICB5bGFiKCJOdW1iZXIgb2YgUGVvcGxlICh0aG91c2FuZHMpIikgKyAKICB4bGFiKE5VTEwpCgojIGJhc2UgcGxvdApuYW1lX3Bsb3QKYGBgCgpgYGB7cn0KbWVkaWFuX3lvYiA8LSB3dGQucXVhbnRpbGUoeCA9IEpvc2VwaCR5ZWFyLCB3ZWlnaHRzID0gSm9zZXBoJGVzdF9hbGl2ZV90b2RheSwgcHJvYnMgPSAwLjUpCm1lZGlhbl95b2IKYGBgCgotIG5vdGUgdGhlIGNsZXZlciB1c2Ugb2YgYGlmZWxzZWAgdG8gY3JlYXRlIGEgbmV3IGhpc3RvZ3JhbSB3aXRoIG9uZSBub24temVybyBiYXIgYXQgYG1lZGlhbl95b2JgCi0gYWRkIHRpdGxlcwotIGFkZCB0ZXh0IGxhYmVscyAoaW1wcm92ZSBmb250cykKLSBhZGQgY3VydmVkIGFycm93Ci0gYWRkIGltcHJvdmVtZW50cwogICAgLSBiZXR0ZXIgZm9udHMKICAgIC0gYmV0dGVyIHRpdGxlcwogICAgLSBiZXR0ZXIgZnJhbWUKICAgIC0gZXRjCmBgYHtyfQpuYW1lX3Bsb3QgPC0gCiAgbmFtZV9wbG90ICsgCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIGNvbG9yID0gIndoaXRlIiwgZmlsbCA9ICIjMDA4ZmQ1IiwgCiAgICAgICAgICAgYWVzKHkgPSBpZmVsc2UoeWVhciA9PSBtZWRpYW5feW9iLCBlc3RfYWxpdmVfdG9kYXkgLyAxMDAwLCAwKSkpIAoKIyBGaWd1cmUgMy4yMjogSm9zZXBocyAoaW1wcm92ZWQpCm5hbWVfcGxvdCArIAogIGdndGl0bGUobGFiZWwgPSAiQWdlIERpc3RyaWJ1dGlvbiBvZiBBbWVyaWNhbiBCb3lzIE5hbWVkIEpvc2VwaCIsIHN1YnRpdGxlID0gIkJ5IHllYXIgb2YgYmlydGgiKSArIAogIGdlb21fdGV4dCh4ID0gMTkzNSwgeSA9IDQwLCBzaXplID0gMy41LCBmYW1pbHkgPSAibW9ubyIsIGxhYmVsID0gIk51bWJlciBvZiBKb3NlcGhzIFxuIGJvcm4gZWFjaCB5ZWFyIikgKyAKICBnZW9tX3RleHQoeCA9IDE5MTUsIHkgPSAxMywgc2l6ZSA9IDMuNSwgZmFtaWx5ID0gIm1vbm8iLCBjb2xvciA9ICIjMDA4ZmQ1IiwgCiAgICAgICAgICAgIGxhYmVsID0gIk51bWJlciBvZiBKb3NlcGhzIFxuIGJvcm4gZWFjaCB5ZWFyIFxuIGVzdGltYXRlZCB0byBiZSBhbGl2ZSBcbiBvbiBKYW4uIDEsIDIwMTQiKSArIAogIGdlb21fdGV4dCh4ID0gMjAwMywgeSA9IDQwLCBzaXplID0gMy41LCBmYW1pbHkgPSAic2FucyIsIGNvbG9yID0gImRhcmtncmF5IiwKICAgICAgICAgICAgbGFiZWwgPSAiVGhlIG1lZGlhblxubGl2aW5nIEpvc2VwaFxuaXMgMzcgeWVhcnMgb2xkLiIpICsgCiAgZ2VvbV9jdXJ2ZSh4ID0gMTk5NSwgeGVuZCA9IDE5NzQsIHkgPSA0MCwgeWVuZCA9IDI0LCAKICAgICAgICAgICAgIGFycm93ID0gYXJyb3cobGVuZ3RoID0gdW5pdCgwLjMsICJjbSIpKSwgY3VydmF0dXJlID0gMC41KSArIAogIHlsaW0oMCwgNDIpICsgCiAgdGhlbWVfZml2ZXRoaXJ0eWVpZ2h0KCkKICAKYGBgCgoKCgojIyBUaHJlZSBJbXBvcnRhbnQgQ29uY2VwdHMgCgoxLiBEYXRhIGNhbiBiZSB1c2VmdWxseSBvcmdhbml6ZWQgaW50byB0YWJsZXMgd2l0aCAiY2FzZXMiIGFuZCAidmFyaWFibGVzLiIgIAogICAgLSBJbiAidGlkeSBkYXRhIiBldmVyeSBjYXNlIGlzIHRoZSBzYW1lIHNvcnQgb2YgdGhpbmcgKGUuZy4gYSBwZXJzb24sIGEgY2FyLCBhIHllYXIsIGEgY291bnRyeSBpbiBhIHllYXIpIAogICAgLSBXZSBzb21ldGltZXMgZXZlbiBtb2RpZnkgZGF0YSBpbiBvcmRlciB0byBjaGFuZ2Ugd2hhdCB0aGUgY2FzZXMgcmVwcmVzZW50IGluIG9yZGVyIHRvIGJldHRlciByZXByZXNlbnQgYSBwb2ludC4KCiMuIERhdGEgZ3JhcGhpY3MgYW5kICJnbHlwaC1yZWFkeSIgZGF0YQogICAgLSBlYWNoIGNhc2UgY29ycmVzcG9uZHMgdG8gYSAiZ2x5cGgiIChtYXJrKSBvbiB0aGUgZ3JhcGgKICAgIC0gZWFjaCB2YXJpYWJsZSB0byBhIGdyYXBoaWNhbCBhdHRyaWJ1dGUgb2YgdGhhdCBnbHlwaCBzdWNoIGFzIHgtIG9yIHktcG9zaXRpb24sIGNvbG9yLCBzaXplLCBsZW5ndGgsIHNoYXBlLCBldGMuIAogICAgLSBzYW1lIGlzIHRydWUgZm9yIG1vcmUgdGVjaG5pY2FsIHRvb2xzIChlLmcuLCBtb2RlbHMpIAoKIy4gV2hlbiBkYXRhIGFyZSBub3QgeWV0IGluIGdseXBoLXJlYWR5IGZvcm0sIHlvdSBjYW4gdHJhbnNmb3JtIChpLmUuIHdyYW5nbGUpIHRoZW0gaW50byBnbHlwaC1yZWFkeSBmb3JtLiAgCiAgICAtIFN1Y2ggdHJhbnNmb3JtYXRpb25zIGFyZSBhY2NvbXBsaXNoZWQgYnkgcGVyZm9ybWluZyBvbmUgb3IgbW9yZSBvZiBhIHNtYWxsIHNldCBvZiBiYXNpYyBvcGVyYXRpb25zIG9uIGRhdGEgdGFibGVzCiAgICAtIFRoaXMgaXMgdGhlIHdvcmsgb2YgZGF0YSAidmVyYnMiIAoKCg==